/**
 * RetryOnExceptionBeanPostProcessor.java
 * 
 * Created on Jun 4, 2008 at 7:13:04 PM
 */
package org.lego4j;

import org.lego4j.retryonexception.RetryOnExceptionPolicyAdvisor;
import org.springframework.aop.framework.ProxyConfig;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.util.ClassUtils;

/**
 * TD fix javadoc!
 * 
 * Bean post-processor that automatically applies retry on exception strategy 
 * to any method that carries the {@link RetryOnException} annotation,
 * adding a corresponding {@link RetryOnExceptionPolicyAdvisor}
 * to the exposed proxy (either an existing AOP proxy or a newly generated
 * proxy that implements all of the target's interfaces).
 *
 * <p>Retries the execution of a method a number of times if
 * a predefined exception is thrown by the method.
 *
 * @author <a href="alexguev@gmail.com">Alexei Guevara</>
 * @version $Revision:$ updated on $Date:$ by $Author:$
 */
public class Lego4jBeanPostProcessor 
    extends ProxyConfig
    implements BeanPostProcessor, BeanClassLoaderAware, Ordered, InitializingBean {

    private static final long serialVersionUID = 5571832433650480007L;
    
    private ClassLoader myBeanClassLoader = ClassUtils.getDefaultClassLoader();

    private AdvisorApplicator myAdvisorApplicator;

    /**
     * {@inheritDoc}
     */
    public Object postProcessAfterInitialization(Object theBean, String theBeanName) throws BeansException {
        return myAdvisorApplicator.apply( theBean );
    }

    /**
     * {@inheritDoc}
     */
    public Object postProcessBeforeInitialization(Object theBean, String theBeanName) throws BeansException {
        return theBean;
    }

    /**
     * {@inheritDoc}
     */
    public void setBeanClassLoader(ClassLoader theClassLoader) {
        this.myBeanClassLoader = theClassLoader;        
    }

    public int getOrder() { 
        // This should run after all other post-processors, so that it can just add
        // an advisor to existing proxies rather than double-proxy.
        return LOWEST_PRECEDENCE;
    }

    /**
     * {@inheritDoc}
     */
    public void afterPropertiesSet() throws Exception {
        myAdvisorApplicator = AdvisorApplicator.createWithProxyConfigAndBeanClassLoader( this, myBeanClassLoader ); 
    }

}
